package initxorm

import (
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/xormplus/xorm"
	"github.com/xormplus/xorm/log"
	"github.com/xormplus/xorm/names"
)

// Engine 根据不同场景实例化一个orm引擎的大写开头的全局变量，以供其他包调用
var Engine = CreateEngine()
var GroupEngine = CreteEngineGroup()

/*
一般情况下如果只操作一个数据库，只需要创建一个engine即可。engine是goroutine安全的。创建完成engine之后，并没有立即连接数据库，
此时可以通过engine.Ping()来进行数据库的连接测试是否可以连接到数据库。另外对于某些数据库有连接超时设置的，可以通过起一个
定期Ping的Go程来保持连接鲜活；
engine可以通过engine.Close来手动关闭，但是一般情况下可以不用关闭，在程序退出时会自动关闭。NewEngine传入的参数和sql.Open
传入的参数完全相同，因此，在使用某个驱动前，请查看此驱动中关于传入参数的说明文档；
*/

// 1. 一个Orm引擎称为Engine，一个Engine一般只对应一个数据库。Engine通过调用xorm.NewEngine生成
func CreateEngine() *xorm.Engine {

	fmt.Println("创建engine被调用了")
	if engine, err := xorm.NewEngine(xorm.MYSQL_DRIVER,
		"d_mymro_oms_admin:n6sdTiwfj1rqBC3h@tcp(759b8d27dbc147789e0f79c7b098c0e3in01.internal.cn-east-3.mysql.rds.myhuaweicloud.com:3306)/d_mymro_oms?charset=utf8"); err != nil {
		return nil
	} else {
		// 通过engine.Ping()来进行数据库的连接测试是否可以连接到数据库
		pingTest(engine, nil)
		// 日志是一个接口，通过设置日志，可以显示SQL，警告以及错误等。有关更多日志相关可查阅：https://www.kancloud.cn/xormplus/xorm/185481
		//在控制台打印出生成的SQL语句（可选项）
		engine.ShowSQL(true)
		//默认的显示级别为INFO（可选项）
		engine.Logger().SetLevel(log.LOG_DEBUG)
		// 设置表名称和字段名称的映射规则
		// 结构体名称和对应的表名称以及结构体field名称与对应的表字段名称相同的命名方式
		engine.SetColumnMapper(names.SameMapper{})
		// 设置struct为驼峰式命名；表结构为下划线，且所有的表名都在结构体自动命名的基础上加一个前缀t_
		tbMapper := names.NewPrefixMapper(names.GonicMapper{}, "t_")
		engine.SetTableMapper(tbMapper)
		// 同步数据库结构（可选项）
		_ = engine.Sync2(new(Test))

		return engine
	}
}

func pingTest(engine *xorm.Engine, engineGroup *xorm.EngineGroup) {
	var err error
	if engine != nil {
		err = engine.Ping()
	} else {
		err = engineGroup.Ping()
	}
	if err != nil {
		panic(any(fmt.Sprintf("创建engine 失败。原因：%s", err.Error())))
	}
}

// 2. 也可以针对特定数据库及数据库驱动使用类似下面的快捷方式创建引擎
func CreateEngine2() *xorm.Engine {

	if engine, err := xorm.NewMySQL(xorm.MYSQL_DRIVER,
		"d_mymro_oms_admin:n6sdTiwfj1rqBC3h@tcp(759b8d27dbc147789e0f79c7b098c0e3in01.internal.cn-east-3.mysql.rds.myhuaweicloud.com:3306)/d_mymro_oms?charset=utf8"); err != nil {
		return nil
	} else {
		return engine
	}
}

// 3. 在xorm里面，可以同时存在多个Orm引擎。对于有大量数据并且需要分区的应用，也可以根据规则来创建多个Engine
func CreateEngine3() [10]*xorm.Engine {

	const total = 10
	var engine [total]*xorm.Engine
	for i := 1; i < total; i++ {
		engine[i], _ = xorm.NewEngine(xorm.MYSQL_DRIVER, fmt.Sprintf("d_mymro_oms_admin:n6sdTiwfj1rqBC3h@tcp(759b8d27dbc147789e0f79c7b098c0e3in01.internal.cn-east-3.mysql.rds.myhuaweicloud.com:3306)/d_mymro_oms%d?charset=utf8", i))
	}

	return engine
}

// 4. 创建引擎组
// 	  在xorm中，通过创建引擎组EngineGroup来实现对从数据库(Master/Slave)读写分离的支持，一个Engine一般只对应一个数据库，
//    而EngineGroup一般则对应一组数据库。EngineGroup通过调用xorm.NewEngineGroup生成。创建完成EngineGroup之后，并没有立即连接数据库，
//    此时可以通过eg.Ping()来进行数据库的连接测试是否可以连接到数据库，该方法会依次调用引擎组中每个Engine的Ping方法。另外对于某些
//    数据库有连接超时设置的，可以通过起一个定期Ping的Go程来保持连接鲜活。EngineGroup可以通过eg.Close()来手动关闭，但是一般情况下
//    可以不用关闭，在程序退出时会自动关闭
func CreteEngineGroup() *xorm.EngineGroup {

	conn := []string{
		"d_mymro_oms_admin:n6sdTiwfj1rqBC3h@tcp(759b8d27dbc147789e0f79c7b098c0e3in01.internal.cn-east-3.mysql.rds.myhuaweicloud.com:3306)/d_mymro_oms?charset=utf8;",
		"d_mymro_oms_admin:n6sdTiwfj1rqBC3h@tcp(759b8d27dbc147789e0f79c7b098c0e3in01.internal.cn-east-3.mysql.rds.myhuaweicloud.com:3306)/d_mymro_oms?charset=utf8;",
		"d_mymro_oms_admin:n6sdTiwfj1rqBC3h@tcp(759b8d27dbc147789e0f79c7b098c0e3in01.internal.cn-east-3.mysql.rds.myhuaweicloud.com:3306)/d_mymro_oms?charset=utf8;",
	}
	// NewEngineGroup方法第三个参数为policies，为Slave给定负载策略，默认为轮询负载策略
	group, err := xorm.NewEngineGroup(xorm.MYSQL_DRIVER, conn)
	if err != nil {
		fmt.Println("create group error: " + err.Error())
		return nil
	} else {
		// 通过EngineGroup.Ping()来进行数据库的连接测试是否可以连接到数据库
		pingTest(nil, group)
		// 返回Master数据库引擎
		//_ = group.Master()
		// 依据给定的负载策略返回一个Slave数据库引擎
		//_ = group.Slave()
		// 返回所有Slave数据库引擎
		//_ = group.Slaves()
		// 设置引擎组负载策略。这里设置为默认的轮询负载策略
		//group.SetPolicy(xorm.RoundRobinPolicy())
		group.ShowSQL(true)
		group.Logger().SetLevel(log.LOG_DEBUG)
		return group
	}
}

// 5. 连接池。engine内部支持连接池接口和对应的函数
func CreateEngine4() *xorm.Engine {

	if engine, err := xorm.NewEngine(xorm.MYSQL_DRIVER,
		"d_mymro_oms_admin:n6sdTiwfj1rqBC3h@tcp(759b8d27dbc147789e0f79c7b098c0e3in01.internal.cn-east-3.mysql.rds.myhuaweicloud.com:3306)/d_mymro_oms?charset=utf8"); err != nil {
		return nil
	} else {
		// 如果需要设置连接池的空闲数大小，可以使用engine.SetMaxIdleConns()来实现
		engine.SetMaxIdleConns(5)
		// 如果需要设置最大打开连接数，则可以使用engine.SetMaxOpenConns()来实现
		engine.SetMaxOpenConns(20)
		return engine
	}
}

type Test struct {
	Id       int64
	Name     string
	Password string
	IsLock   int8 `xorm:" -> 'is_lock'"`
}
